package com.peak.distribution.web.agent;

import com.peak.distribution.entity.admin.DisSmsTemplate;
import com.peak.distribution.entity.agent.DisAgent;
import com.peak.distribution.enums.SmsType;
import com.peak.distribution.exception.DistributionError;
import com.peak.distribution.exception.DistributionException;
import com.peak.distribution.jms.JmsProducerHandler;
import com.peak.distribution.manager.admin.DisSmsTemplateManager;
import com.peak.distribution.service.agent.DisAgentService;
import com.peak.distribution.tools.QrCodes;
import com.peak.distribution.tools.SpringSecuritys;
import com.peak.distribution.vo.agent.DisAgentVo;
import com.peak.distribution.web.CaptchaController.CaptchaName;
import com.peak.distribution.web.validator.Valid;
import com.peak.distribution.web.validator.ValidateRule;
import com.peak.distribution.web.validator.ValidateRuleBuilder;
import com.peak.distribution.web.validator.Validation;
import com.peak.distribution.web.validator.method.*;
import com.peak.distribution.web.validator.method.Number;
import com.peak.spring.boot.api.repository.FilterParam;
import com.peak.spring.boot.api.repository.FilterParam.Operator;
import com.peak.spring.boot.api.web.JsonMessage;
import com.peak.spring.boot.api.web.JsonPage;
import com.peak.spring.boot.builder.repository.FilterParamBuilder;
import com.peak.spring.boot.builder.web.JsonBuilder;
import com.peak.spring.boot.core.exception.Exceptions;
import com.peak.spring.boot.core.web.BaseController;
import com.peak.spring.boot.tools.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.net.URI;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/agent")
@Slf4j
public class DisAgentController extends BaseController<DisAgent, DisAgentVo> {
	
	@Autowired
	private DisAgentService agentService;
	
	@Autowired
	private JmsProducerHandler jmsProducerHandler;
	
	@Autowired
	private DisSmsTemplateManager smsTemplateManager;
	
	@Value("${aes.key}")
	private String aseKey;
	
	@PostMapping("/change/head")
	public JsonMessage changeHead(HttpServletRequest request) {
		Map<String, Object> params = Servlets.getParametersStartingWith(request, "");
		List<ValidateRule> rules = ValidateRuleBuilder.create()
				.rule("headUrl", "头像地址").methods(Require.class, UrlString.class, ImageSuffix.class)
				.build();
		Valid valid = Validation.buildDefaultValidatorFactory().rule(rules).validate(params);
		if (valid.isValid()) {
			DisAgent agent = agentService.getCurrentAgent();
			agent.setHeadUrl(Converts.toString(params.get("headUrl")));
			baseManager.save(agent);
			return JsonBuilder.message().success().build();
		} else {
			return JsonBuilder.message().fail().content(valid.getErrorMessages()).build();
		}
	}
	
	@PostMapping("/update/current/info")
	public JsonMessage updateInfo(HttpServletRequest request) {
		Map<String, Object> params = Servlets.getParametersStartingWith(request, "");
		List<ValidateRule> rules = ValidateRuleBuilder.create()
				.rule("name", "姓名").methods(Require.class, CNString.class, Length.class).methodParam(Length.class).add("max", 8).end()
				.and()
				.rule("mobileNo", "手机号码").methods(Require.class, MobileNo.class)
				.and()
				.rule("qq", "QQ号码").methods(Length.class, Number.class)
					.methodParam(Length.class).add("min", 5).add("max", 11).end()
					.methodParam(Number.class).add("msgArgs", "整数").end()
				.and()
				.rule("email", "邮箱").methods(Email.class, Length.class).methodParam(Length.class).add("max", 255).end()
				.and()
				.rule("bankCard", "银行卡").methods(BankCard.class)
					.methodParam(BankCard.class).add("bank", params.get("bank")).end()
				.and()
				.rule("zhifubao", "支付宝账号").methods(Length.class)
					.methodParam(Length.class).add("max", 255).end()
				.and()
				.rule("wxPay", "微信账号").methods(Length.class)
					.methodParam(Length.class).add("max", 255).end()
				.build();
		Valid valid = Validation.buildDefaultValidatorFactory().rule(rules).validate(params);
		if (valid.isValid()) {
			DisAgent agent = agentService.getCurrentAgent();
			agentService.updateAgentInfo(params, agent);
			return JsonBuilder.message().success().build();
		} else {
			return JsonBuilder.message().fail().content(valid.getErrorMessages()).build();
		}
	}
	
	@PostMapping("/change/password")
	public JsonMessage changePassword(HttpServletRequest request) {
		Map<String, Object> params = Servlets.getParametersStartingWith(request, "");
		agentService.changePassword(params);
		SpringSecuritys.logout(request);
		return JsonBuilder.message().success().build();
	}

	@PostMapping("/reset/password")
	public JsonMessage resetPassword(HttpServletRequest request) {
		Map<String, Object> params = Servlets.getParametersStartingWith(request, "");
		agentService.resetPassword(params);
		return JsonBuilder.message().success().build();
	}
	
	@PostMapping("/check/mobile/code")
	public JsonMessage checkMobileCode(HttpServletRequest request) {
		Map<String, Object> params = Servlets.getParametersStartingWith(request, "");
		String mobileNo = Converts.toString(params.get("mobileNo"));
		String captchaCode = Converts.toString(params.get("captchaCode"));
		// 会自己抛出异常，系统自动捕获
		agentService.checkMobileCode(mobileNo, captchaCode, SmsType.FORGOT_PASSWORD);
		return JsonBuilder.message().success().build();
	}

	@PostMapping("/sub/list")
	public JsonPage subList(HttpServletRequest request) {
		String parentIdFilter = "parent.id";
		List<FilterParam> filterParams = FilterParamBuilder.create().parseRequest(request).build();
		boolean hasParent = filterParams.stream().anyMatch(p -> parentIdFilter.equals(p.getFieldName()));
		if (!hasParent) {
			filterParams.add(new FilterParam("parent.id", Operator.EQ, agentService.getCurrentAgentId()));
		}
		PageRequest pageRequest = Servlets.getPages(request);
		Page<DisAgent> page = baseManager.findPage(filterParams, pageRequest);
		JsonPage json = JsonBuilder.page().success().page(page).convert(DisAgentVo.class).build();
		return json;
	}
	
	@PostMapping("/sub/add")
	public JsonMessage subAdd(HttpServletRequest request) {
		Map<String, Object> map = Servlets.getParametersStartingWith(request, "");
		Valid valid = addValidator(map);
		if (valid.isValid()) {
			DisAgent agent = agentService.getCurrentAgent();
			String captchaCode = Converts.toString(map.get("captchaCode"));
			String mobileNo = Converts.toString(map.get("mobileNo"));
			// 检查验证码
//			agentService.checkMobileCode(mobileNo, captchaCode, SmsType.SUBAGENT_REGIST);
			// 添加代理
			agentService.addSubAgent(map, agent, true);
			return JsonBuilder.message().success().build();
		} else {
			return JsonBuilder.message().fail().content(valid.getErrorMessages()).build();
		}
	}
	
	@PostMapping("/current")
	public JsonMessage current(HttpServletRequest request) {
		DisAgent agent = agentService.getCurrentAgent();
		if (Emptys.isEmpty(agent)) {
			throw new DistributionException(DistributionError.AGENT_NOT_FOUND);
		}
		return JsonBuilder.message().success().content(agent).convert(DisAgentVo.class).build();
	}
	
	@GetMapping("/current/qrcode")
	public void currentQrcode(HttpServletRequest request, HttpServletResponse response) {
		// 设置相应类型,告诉浏览器输出的内容为图片
		response.setContentType("image/jpg");
		// 不缓存此内容
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expire", 0);
		DisAgent agent = agentService.getCurrentAgent();
		log.info("============生成个人二维码图片：{}, ", Servlets.getIp(request), agent.getMobileNo());
		try {
			Map<String, Object> param = Servlets.getParametersStartingWith(request, "");
			String localServer = param.get("serverUrl") + request.getServletContext().getContextPath();
			byte[] bytesId = Converts.toString(agent.getId()).getBytes(Encodes.DEFAULT_URL_ENCODING2);
			byte[] bytesKey = aseKey.getBytes(Encodes.DEFAULT_URL_ENCODING2);
			String paramId = Encodes.encodeHex(Cryptos.aesEncrypt(bytesId, bytesKey));
			String recommendUrl = localServer + "/recommend/" + paramId;
			log.info(recommendUrl);
			String headUrl = agent.getHeadUrl();
			if (Emptys.isEmpty(headUrl)) {
				headUrl = "/images/" + (agent.getSex() != null && agent.getSex() ? "header_male.png" : "header_female.png");
			}
			if (StringUtils.startsWith(headUrl, "/")) {
				headUrl = localServer + headUrl;
			}
			BufferedImage image = QrCodes.create().content(recommendUrl).logo().imageURI(new URI(headUrl)).end().build();
			ImageIO.write(image, "jpg", response.getOutputStream());
		} catch (Exception e) {
			throw Exceptions.unchecked(e);
		}
	}
	
	@PostMapping("/send/sms")
	public JsonMessage sendSms(HttpServletRequest request) {
		// 获取参数，由于有payload和parameter两种参数，只好用封装好的方法获取了
		Map<String, Object> params = Servlets.getParametersStartingWith(request, "");
		// 判断用户输入的图片验证码和后台session保存的图片验证码是否一致,暂时使用httpsession来保存，以后看心情做其他存储，比如ehcache，redis等，只有一个字：懒
		String imageCode = Converts.toString(params.get("code"));
		String mobileNo = Converts.toString(params.get("mobileNo"));
		CaptchaName captchaName = null;
		try {
			captchaName = CaptchaName.valueOf(Converts.toString(params.get("captchaName")));
		} catch (Exception e) {
			throw new DistributionException(DistributionError.CAPTCHA_NAME_NOT_FOUND);
		}
		// 从session中取出
		String sessionCode = Converts.toString(request.getSession().getAttribute(captchaName.name()));
		Date sessionCodeTime = Converts.toDate(request.getSession().getAttribute(captchaName.name() + "_time"));
		// 空的一般就是使用过了，需要刷新
		if (Emptys.isEmpty(sessionCode) || Emptys.isEmpty(sessionCodeTime)) {
			throw new DistributionException(DistributionError.CAPTCHA_CODE_EXPIRE);
		}
		// 有效5分钟
		Date now = Dates.addMinute(Dates.now(), -5);
		// 超时
		if (sessionCodeTime.before(now)) {
			throw new DistributionException(DistributionError.CAPTCHA_CODE_EXPIRE);
		}
		// 不一致
		if (!StringUtils.equalsIgnoreCase(imageCode, sessionCode)) {
			throw new DistributionException(DistributionError.CAPTCHA_CODE_NOT_EQUAL);
		}
		// 验证通过就不需要了，可以删除了
		request.getSession().removeAttribute(captchaName.name());
		request.getSession().removeAttribute(captchaName.name() + "_time");
		
		// 生成随机数，好像新版的这个方法被废弃了，好可惜
		String code = RandomStringUtils.random(6, false, true);
		// 加入到队列发送短信
		SmsType smsType = null;
		switch (captchaName) {
		case agent_regist_code:
			smsType = SmsType.SUBAGENT_REGIST;
			boolean mobileUnique = baseManager.checkUnique(FilterParamBuilder.create().eq("mobileNo", mobileNo).build(), new DisAgent());
			if (!mobileUnique) {
				throw new DistributionException(DistributionError.AGENT_MOBILE_EXIST);
			}
			break;
		case user_forgot_code:
			smsType = SmsType.FORGOT_PASSWORD;
			break;
		default:
			break;
		}
		// 找到短信模版
		DisSmsTemplate template = smsTemplateManager.getTemplateByType(smsType);
		if (template == null) {
			throw new DistributionException(DistributionError.SMS_TEMPLATE_NOT_FOUND);
		}
		jmsProducerHandler.sendSmsJms(smsType, mobileNo, MessageFormat.format(template.getTemplate(), code));
		return JsonBuilder.message().success().build();
	}
	
	@PostMapping("/recommend/{aesId}")
	public JsonMessage getRecommender(@PathVariable String aesId) {
		Integer id = decodeAesId(aesId);
		return super.get(id);
	}

	private Integer decodeAesId(String aesId) {
		byte[] bytesId = Encodes.decodeHex(aesId);
		byte[] bytesKey = aseKey.getBytes(Encodes.DEFAULT_URL_ENCODING2);
		Integer id = Converts.toInteger(Cryptos.aesDecrypt(bytesId, bytesKey));
		return id;
	}
	
	@PostMapping("/recommend/sub/add")
	public JsonMessage recommendSubAdd(HttpServletRequest request) {
		Map<String, Object> map = Servlets.getParametersStartingWith(request, "");
		// method 处理传参的情况还需要想想
		Valid valid = addValidator(map);
		if (valid.isValid()) {
			// 校验推荐人的id
			Integer refereeId = Converts.toInteger(map.get("refereeId"));
			Integer aesId = decodeAesId(Converts.toString(map.get("aesId")));
			if (Emptys.isEmpty(aesId) || !refereeId.equals(aesId)) {
				throw new DistributionException(DistributionError.RECOMMEND_AGENT_NOT_FOUND);
			}
			DisAgent agent = baseManager.getOne(refereeId);
			String captchaCode = Converts.toString(map.get("captchaCode"));
			String mobileNo = Converts.toString(map.get("mobileNo"));
			// 检查验证码
			agentService.checkMobileCode(mobileNo, captchaCode, SmsType.SUBAGENT_REGIST);
			// 添加代理
			agentService.addSubAgent(map, agent, true);
			return JsonBuilder.message().success().build();
		} else {
			return JsonBuilder.message().fail().content(valid.getErrorMessages()).build();
		}
	}

	private Valid addValidator(Map<String, Object> map) {
		List<ValidateRule> rules = ValidateRuleBuilder.create()
			.rule("name", "姓名").methods(Require.class, CNString.class, Length.class).methodParam(Length.class).add("max", 8).end()
			.and()
			.rule("mobileNo", "手机号码").methods(Require.class, MobileNo.class)
			.and()
			.rule("email", "邮箱").methods(Email.class, Length.class).methodParam(Length.class).add("max", 255).end()
			.and()
			.rule("password", "密码").methods(Length.class, SameTo.class)
				.methodParam(Length.class).add("min", 6).add("max", 32).end()
				.methodParam(SameTo.class).add("other", map.get("password2")).end()
			.and()
			.rule("bankCard", "银行卡").methods(BankCard.class).methodParam(BankCard.class).add("bank", map.get("bank")).end()
			.and()
			.rule("zhifubao", "支付宝账号").methods(Length.class).methodParam(Length.class).add("max", 255).end()
			.and()
			.rule("wxPay", "微信账号").methods(Length.class).methodParam(Length.class).add("max", 255).end()
			.build();
		
		Valid valid = Validation.buildDefaultValidatorFactory().rule(rules).validate(map);
		return valid;
	}
	
	@PostMapping("/audit/{id}")
	public JsonMessage audit(HttpServletRequest request, @PathVariable("id") Integer id) {
		DisAgent agent = baseManager.getOne(id);
		agent.setAuditStatus(Boolean.TRUE);
		baseManager.save(agent);
		return JsonBuilder.message().success().build();
	}
	
	@PostMapping("/audit/count")
	public JsonMessage countOrder(HttpServletRequest request) {
		int count = baseManager.count(FilterParamBuilder.create().eq("auditStatus", false).build());
		return JsonBuilder.message().success().content(count).build();
	}
}
